package org.covalence.core.util;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;

import org.apache.log4j.Logger;
import org.covalence.core.Observable;

@SuppressWarnings("unchecked")
public class CSet implements Observable, Set {

	private Set _delegate;
	
	private Observable _parent;
	
	private String _propertyName;
	
	private static Logger log = Logger.getLogger(CSet.class);
	
	public CSet(Object delegate) {
		super();
		this._delegate = (Set) delegate;
	}

	public void addNestedObservable(Observable obs, String propertyName) {
		throw new UnsupportedOperationException("Cannot nest observables inside CSet");
	}

	public void addPropertyChangeListener(PropertyChangeListener listener) {
		this._parent.removePropertyChangeListener(listener);
	}

	public Object getParent() { return this._parent; }

	public PropertyChangeListener[] getPropertyChangeListeners() { return null; }

	public void removePropertyChangeListener(PropertyChangeListener listener) {
		this._parent.removePropertyChangeListener(listener);
	}

	public void setNestedPropertyName(String propertyName) {
		this._propertyName = propertyName;
	}

	public void setParent(Observable parent) {
		this._parent = parent;
	}

	public void propertyChange(PropertyChangeEvent evt) {}
	
	public boolean add(Object o) {
		boolean result = _delegate.add(o);
		_notify();
		return result;
	}
	
	public boolean addAll(Collection c) {
		boolean result = _delegate.addAll(c);
		_notify();
		return result;
	}

	public void clear() {
		_delegate.clear();
		_notify();
	}
	
	public boolean contains(Object o) {
		return _delegate.contains(o);
	}
	
	public boolean containsAll(Collection c) {
		return _delegate.containsAll(c);
	}
	
	public boolean equals(Object o) {
		return _delegate.equals(o);
	}
	
	public int hashCode() {
		return _delegate.hashCode();
	}
	
	public boolean isEmpty() {
		return _delegate.isEmpty();
	}
	
	public Iterator iterator() {
		return _delegate.iterator();
	}
	
	public boolean remove(Object o) {
		boolean result = _delegate.remove(o);
		_notify();
		return result;
	}
	
	public boolean removeAll(Collection c) {
		boolean result = _delegate.removeAll(c);
		_notify();
		return result;
	}
	
	public boolean retainAll(Collection c) {
		boolean result = _delegate.retainAll(c);
		_notify();
		return result;
	}
	
	public int size() {
		return _delegate.size();
	}
	
	public Object[] toArray() {
		return _delegate.toArray();
	}
	
	public Object[] toArray(Object[] a) {
		return _delegate.toArray(a);
	}
	
	private void _notify() {
		if (_propertyName == null) {
			log.warn("Property name was never set, cannot notify.  " +
					"Try nesting this object inside another observable.");
		} else if (_parent == null) {
			log.warn("Parent is null, cannot notify.  " +
					"Make sure the parent property is set.");
		} else {
			_parent.propertyChange(
					new PropertyChangeEvent(_parent, _propertyName, null, this));
		}
	}
}
